package cn.hamster3.mc.plugin.ball.velocity;

import cn.hamster3.mc.plugin.ball.common.api.BallAPI;
import cn.hamster3.mc.plugin.ball.common.entity.BallPlayerInfo;
import cn.hamster3.mc.plugin.ball.common.event.BallActions;
import cn.hamster3.mc.plugin.ball.common.event.server.ServerOnlineEvent;
import cn.hamster3.mc.plugin.ball.velocity.api.CoreVelocityAPI;
import cn.hamster3.mc.plugin.ball.velocity.listener.BallVelocityListener;
import cn.hamster3.mc.plugin.ball.velocity.listener.BallVelocityMainListener;
import cn.hamster3.mc.plugin.ball.velocity.listener.UpdatePlayerInfoListener;
import cn.hamster3.mc.plugin.ball.velocity.util.BallVelocityUtils;
import com.google.inject.Inject;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Dependency;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import lombok.Getter;
import net.kyori.adventure.text.Component;
import org.slf4j.Logger;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Objects;
import java.util.logging.Level;

@Plugin(
        id = "hamster-ball",
        name = "HamsterBall",
        version = BuildConstants.VERSION,
        description = BuildConstants.DESCRIPTION,
        authors = {"MiniDay"},
        dependencies = @Dependency(id = "hamster-core")
)
public class HamsterBallPlugin {
    @Getter
    private static HamsterBallPlugin instance;
    @Getter
    private final java.util.logging.Logger logger;
    @Getter
    private final Logger slf4jLogger;
    @Getter
    private final ProxyServer proxyServer;
    @Getter
    private final File dataFolder;

    @Inject
    public HamsterBallPlugin(Logger slf4jLogger, ProxyServer proxyServer, @DataDirectory Path dataPath) {
        long start = System.currentTimeMillis();
        logger = java.util.logging.Logger.getLogger("hamster-ball");
        this.slf4jLogger = slf4jLogger;
        this.proxyServer = proxyServer;
        dataFolder = dataPath.toFile();
        logger.info("仓鼠球正在初始化");
        instance = this;
        try {
            File dataFolder = getDataFolder();
            if (dataFolder.mkdir()) {
                logger.info("已生成插件存档文件夹");
            }
            File configFile = new File(dataFolder, "config.yml");
            if (!configFile.exists()) {
                Files.copy(
                        Objects.requireNonNull(getClass().getResourceAsStream("/config.yml")),
                        configFile.toPath(),
                        StandardCopyOption.REPLACE_EXISTING
                );
            }
            CoreVelocityAPI.init(configFile);
            logger.info("已初始化 BallAPI");
        } catch (Exception e) {
            slf4jLogger.error("BallAPI 初始化失败", e);
            proxyServer.shutdown(Component.text("由于 HamsterBall 初始化失败, 服务器将立即关闭"));
        }
        long time = System.currentTimeMillis() - start;
        logger.info("仓鼠球初始化完成，总计耗时 " + time + " ms");
    }

    @Subscribe(order = PostOrder.EARLY)
    public void onProxyInitialization(ProxyInitializeEvent event) {
        long start = System.currentTimeMillis();
        java.util.logging.Logger logger = getLogger();
        logger.info("仓鼠球正在启动");
        try {
            CoreVelocityAPI.getInstance().enable();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "仓鼠球启动失败", e);
            logger.info("由于仓鼠球启动失败，服务器将立即关闭");
            proxyServer.shutdown(Component.text("仓鼠球启动失败"));
            return;
        }
        BallAPI.getInstance().getEventBus().register(BallVelocityListener.INSTANCE);
        logger.info("已注册监听器 BallBungeeListener");
        proxyServer.getEventManager().register(this, BallVelocityMainListener.INSTANCE);
        logger.info("已注册监听器 BallBungeeMainListener");
        proxyServer.getEventManager().register(this, UpdatePlayerInfoListener.INSTANCE);
        logger.info("已注册监听器 UpdatePlayerInfoListener");

        if (BallAPI.getInstance().getBallConfig().isGameServerUpdatePlayerInfo()) {
            BallAPI.getInstance().subscribePatterns("*" + BallAPI.PLAYER_INFO_CHANNEL);
        } else {
            BallAPI.getInstance().subscribeIgnorePrefix(BallAPI.PLAYER_INFO_CHANNEL);
        }
        BallAPI.getInstance().sendRawBallMessage(
                BallAPI.BALL_CHANNEL, BallActions.ServerOnline.name(),
                new ServerOnlineEvent(BallAPI.getInstance().getLocalServerInfo())
        );
        // 移除失效的在线玩家
        BallAPI.getInstance().getAllPlayerInfo().values()
                .stream()
                .filter(BallPlayerInfo::isOnline)
                .filter(o -> BallAPI.getInstance().isLocalServer(o.getProxyServer()))
                .forEach(playerInfo -> {
                    playerInfo.setOnline(false);
                    BallVelocityUtils.uploadPlayerInfo(playerInfo);
                });
        long time = System.currentTimeMillis() - start;
        logger.info("仓鼠球启动完成，总计耗时 " + time + " ms");
    }

    @Subscribe(order = PostOrder.LATE)
    public void onProxyShutdown(ProxyShutdownEvent event) {
        long start = System.currentTimeMillis();
        java.util.logging.Logger logger = getLogger();
        logger.info("仓鼠球正在关闭");
        try {
            CoreVelocityAPI.getInstance().disable();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "关闭仓鼠球时遇到了一个异常", e);
        }
        long time = System.currentTimeMillis() - start;
        logger.info("仓鼠球已关闭，总计耗时 " + time + " ms");
    }
}